package cn.com.anysdk.oss.impl;

import cn.com.anysdk.oss.api.IOssService;
import cn.com.anysdk.oss.api.IOssConfig;
import cn.com.anysdk.oss.api.UploadOptions;
import cn.com.anysdk.oss.exception.OssException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;

/**
 * 阿里云 OSS 实现
 */
@Slf4j
public class AliyunOssService implements IOssService {
    private final OSS ossClient;
    private final IOssConfig config;

    public AliyunOssService(IOssConfig config) {
        this.config = config;
        this.ossClient = new OSSClientBuilder()
                .build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
    }

    @Override
    public String uploadFile(String objectKey, File file) {
        return uploadFile(objectKey, file, UploadOptions.publicFile());
    }

    @Override
    public String uploadFile(String objectKey, InputStream inputStream, long size) {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(size);
        try {
            PutObjectResult result = ossClient.putObject(config.getBucketName(), objectKey, inputStream, metadata);
            log.debug("Upload file success, path: {}, ETag: {}", objectKey, result.getETag());
            return getFileUrl(objectKey);
        } catch (Exception e) {
            throw new OssException("Upload file failed: " + e.getMessage(), e);
        }
    }

    @Override
    public String uploadFile(String objectKey, File file, UploadOptions options) {
        try {
            ObjectMetadata metadata = createMetadata(options);
            PutObjectResult result = ossClient.putObject(config.getBucketName(), objectKey, file, metadata);
            log.debug("Upload file success, path: {}, ETag: {}", objectKey, result.getETag());
            return getFileUrl(objectKey, options.isPrivate() ? options.getExpireTime() : null);
        } catch (Exception e) {
            throw new OssException("Upload file failed: " + e.getMessage(), e);
        }
    }

    @Override
    public InputStream downloadFile(String objectKey) {
        try {
            OSSObject ossObject = ossClient.getObject(config.getBucketName(), objectKey);
            return ossObject.getObjectContent();
        } catch (Exception e) {
            throw new OssException("Download file failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void deleteFile(String objectKey) {
        try {
            ossClient.deleteObject(config.getBucketName(), objectKey);
        } catch (Exception e) {
            throw new OssException("Delete file failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void deleteFiles(List<String> objectKeys) {
        try {
            DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(config.getBucketName());
            deleteRequest.setKeys(objectKeys);
            ossClient.deleteObjects(deleteRequest);
        } catch (Exception e) {
            throw new OssException("Delete files failed: " + e.getMessage(), e);
        }
    }

    @Override
    public String getFileUrl(String objectKey) {
        return getFileUrl(objectKey, null);
    }

    @Override
    public String getSignedUrl(String objectKey, long expireSeconds) {
        return getFileUrl(objectKey, expireSeconds);
    }

    @Override
    public boolean doesObjectExist(String objectKey) {
        try {
            return ossClient.doesObjectExist(config.getBucketName(), objectKey);
        } catch (Exception e) {
            log.error("Check file exists failed: " + e.getMessage(), e);
            return false;
        }
    }

    private String getFileUrl(String objectKey, Long expireTime) {
        try {
            if (config.isPrivateMode() || expireTime != null) {
                Date expiration = new Date(System.currentTimeMillis() + (expireTime != null ? expireTime * 1000 : 3600 * 1000));
                URL url = ossClient.generatePresignedUrl(config.getBucketName(), objectKey, expiration);
                return url.toString();
            } else {
                return String.format("https://%s.%s/%s", config.getBucketName(), config.getEndpoint(), objectKey);
            }
        } catch (Exception e) {
            throw new OssException("Generate URL failed: " + e.getMessage(), e);
        }
    }

    private ObjectMetadata createMetadata(UploadOptions options) {
        ObjectMetadata metadata = new ObjectMetadata();
        if (options.getContentType() != null) {
            metadata.setContentType(options.getContentType());
        }
        if (options.getAcl() != null) {
            metadata.setObjectAcl(com.aliyun.oss.model.CannedAccessControlList.parse(options.getAcl()));
        }
        return metadata;
    }
}